package simulator;

import java.util.concurrent.PriorityBlockingQueue;

import simulator.queue.Event;
import simulator.queue.EventComparator;
import simulator.queue.Item;
import simulator.util.ExponentialNumberGenerator;

public class System 
{
	private final PriorityBlockingQueue<Event> eventQueue = new PriorityBlockingQueue<Event>(100, new EventComparator());
	private double timeLine = 0;
	private int eventId = 0;
	private int itemId = 0;
	
	public static int ITEM_QUEUE_ID_QUEUE_1 = 1;
	public static int ITEM_QUEUE_ID_QUEUE_2 = 2;
	
	public boolean addEventExitServerEvent(double time, Item item)
	{
		Event event = new Event(generateEventId(), time, Event.TYPE_EXIT_SERVER, item);
		return this.eventQueue.add(event);
	}
	
	public int generateEventId()
	{
		return eventId++;
	}
	
	public int generateItemId()
	{
		return itemId++;
	}
	
	public void startEventGenerator(double randon, double lambdaRate)
	{
		
		Server server = new Server(1, this);
		// generates the first event
		int eventId = generateEventId();
		double nextEventTime = 0;
		Event firstEvent = new Event(eventId, nextEventTime, Event.TYPE_QUEUE1_ARRIVE, new Item(generateItemId(), nextEventTime, ITEM_QUEUE_ID_QUEUE_1));
		eventQueue.add(firstEvent);
		
		while(!eventQueue.isEmpty())
		{
			
			// process the current event
			Event currentEvent = eventQueue.remove();
			timeLine = currentEvent.getTime();
			Item currentItem = currentEvent.getItem();
			switch (currentEvent.getType()) 
			{
				case Event.TYPE_QUEUE1_ARRIVE:
				{
					currentItem.addEvent(currentEvent);
					//add item in queue 1 to process
					server.addItemOnQueue1(currentItem);
					// calculates the next exponential time
					nextEventTime = timeLine + ExponentialNumberGenerator.generate(randon, lambdaRate);
					// creates a new queue 1 arrive event.
					Item item = new Item(generateItemId(), timeLine, ITEM_QUEUE_ID_QUEUE_1);
					Event nextEvent = new Event(generateEventId(), timeLine, Event.TYPE_QUEUE1_ARRIVE, item);
					// add the event on event queue
					eventQueue.add(nextEvent);
					
					break;
				}
				case Event.TYPE_QUEUE2_ARRIVE:
				{
					currentItem.addEvent(currentEvent);
					//add item in queue 2 to process
					server.addItemOnQueue2(currentItem);
					break;
				}
				//TODO: should it exists?
				case Event.TYPE_SERVER_ARRIVE:
				{
					currentItem.addEvent(currentEvent);
/*					if(server.setitemInService == null)
					{
						itemInService = currentItem;
					}
					else
					{
						//process the interruption
						if(itemInService.getCurrentItemQueueId() == ITEM_QUEUE_ID_QUEUE_2 && currentItem.getCurrentItemQueueId() == ITEM_QUEUE_ID_QUEUE_1)
						{
							Event nextEvent = new Event(eventId, timeLine, Event.TYPE_INTERRUPTION, currentItem);
							eventQueue.add(nextEvent);
						}
						else
						{
							//process the item
						}
					}
					
*/					
					break;
				}
				case Event.TYPE_INTERRUPTION:
				{
					currentItem.addEvent(currentEvent);
					eventQueue.add(new Event(eventId, timeLine, Event.TYPE_SERVER_ARRIVE, currentItem));
					
					break;
				}
				case Event.TYPE_EXIT_SERVER:
				{
					currentItem.addEvent(currentEvent);
					if(currentItem.getCurrentItemQueueId() == ITEM_QUEUE_ID_QUEUE_1)
						eventQueue.add(new Event(eventId, timeLine, Event.TYPE_QUEUE2_ARRIVE, currentItem));
					else
						eventQueue.add(new Event(eventId, timeLine, Event.TYPE_EXIT_SYSTEM, currentItem));
					
					break;
				}
			}
		}
	}
	
	
}
